const Assert = require('./Assert.js');

class URL{
    constructor(href){
        Assert.isGeneralTrue(href, "construct 1 argument required, but only 0 present.");
        Assert.isTrue(this.#parse(href), "url format illegal.");
        this.#format();
    }
    #getDefault(param, defaultVal){
        if (param) {
            return param;
        }
        return defaultVal;
    }
    #format(){
        this.protocol = this.#getDefault(this.protocol, "");
        this.host = this.#getDefault(this.host, "");
        this.hostname = this.#getDefault(this.hostname, "");
        this.port = this.#getDefault(this.port, "");
        this.path = this.#getDefault(this.path, "/");
        this.search = this.#getDefault(this.search, "");
        while (this.search.endsWith("&")) {
            this.search.substring(0, this.search.length - 1);
        }
        this.hash = this.#getDefault(this.hash, "");
        this.href = this.protocol + "//" + this.host + this.path + this.search + this.hash;
    }
    #parse(href){
        let index = href.indexOf("://");
        let index2 = href.indexOf("?");
        index2 = index2==-1?Number.MAX_SAFE_INTEGER:index2;
        let index3 = href.indexOf("#");
        index3 = index3==-1?Number.MAX_SAFE_INTEGER:index2;
        let min = Math.min(index==-1?Number.MAX_SAFE_INTEGER:index, index2, index3);
        // “://”出现的位置必须在“？”和“#”之前
        if (min === index2 || min === index3) {
            return false;
        }
        if (index == -1){
            return false;
        }
        // 拿到协议
        this.protocol = href.substring(0, index + 1);
        // 删除协议后的url
        href = href.substring(index + 3);
        index = href.indexOf("/");
        index = index == -1 ? href.indexOf("?") : index;
        index = index == -1 ? href.indexOf("#") : index;
        // 拿到主机
        this.host = href;
        if (index != -1){
            this.host = href.substring(0, index);
        }
        // 移除主机
        href = href.substring(index==-1?href.length:index);
        // 默认主机名 无端口号
        this.hostname = this.host;
        index = this.host.indexOf(":");
        // 如果存在端口号分隔符
        if (index != -1){
            // 端口号分隔符后未跟端口号
            if (index + 1 >= this.host.length){
                return false;
            }
            this.hostname = this.host.substring(0, index);
            this.port = this.host.substring(index + 1);
        }
        // 获取hash分隔符
        index = href.indexOf("#");
        if (index != -1) {
            this.hash = href.substring(index);
            // 移除hash
            href = href.substring(0, index);
        }

        // 获取path分隔符
        index = href.indexOf("?");
        if (index != -1) {
            this.search = href.substring(index);
            // 移除path
            href = href.substring(0, index);
        }
        this.path = href;
        return true;
    }
    toString(){
        return this.protocol + "//" + this.host + this.path + this.search + this.hash;
    }
    print(){
        return "href=" + this.href + "\nprotocol=" + this.protocol + "\nhost=" + this.host + "\nhostname=" + this.hostname +
            "\nport=" + this.port + "\npath=" + this.path + "\nsearch=" + this.search + "\nhash=" + this.hash;
    }
    resolve(path){
        return URL.resolve(this, path);
    }
    static #proHostname(url){
        if (!(url instanceof URL)) {
            throw "Type mismatch"
        }
        return url.protocol + "//" + url.host;
    }
    static resolve(baseUrl, url){
        if (!(baseUrl instanceof URL)) {
            throw "Type mismatch"
        }
        if (url.startsWith("//")) {
            return new URL(baseUrl.protocol + url);
        }
        if (url.startsWith("/")) {
            return new URL(URL.#proHostname(baseUrl) + url);
        }

        try{
            let rst = new URL(url);
            return rst;
        }
        catch(a){
        }
        let basePath = baseUrl.path.split("/");
        let urlPath = url.split("/");
        let index = basePath.length - 1;
        for (let i = 0, l = urlPath.length; i < l; i++) {
            if (".." == urlPath[i]) {
                index --;
                if (index < 1) {
                    throw "The url="+url+" format is not legal";
                }
                continue;
            }
            if ("." == urlPath[i]) {
                continue;
            }
            basePath[index] = urlPath[i];
            index ++;
        }
        let result = "";
        // 第0个必定为空串
        for (let i = 1; i < index; i++) {
            result += "/" + basePath[i];
        }
        return new URL(URL.#proHostname(baseUrl) + result);
    }
}
module.exports = exports = URL;